#pragma once
#include "stdafx.h"
#include "CheckFitness.h"
#include "GbcParser.h"
#include "CornerDetect.h"
#include <string>
#include "ScriptParser.h"

double SNU_g_adAverages[NUM_OF_BILLTYPES][NUM_OF_BILLDIRECTION][8];
int SNU_g_anCnt[NUM_OF_BILLTYPES][NUM_OF_BILLDIRECTION];
double SNU_g_adThreshHold[NUM_OF_BILLTYPES][NUM_OF_BILLDIRECTION];
double SNU_g_adSoilThreshHold[NUM_OF_BILLTYPES][NUM_OF_BILLDIRECTION];

double SNU_GetAverageRGB_InArray(char** ppImageArrays, CCornerInfo* pCornerInfo, int nImageNum)
{
	static const int GRIDSIZE = 7;
	double dRet = 0;
    int nWidth = pCornerInfo->GetWidth();
    int nHeight = pCornerInfo->GetHeight();
	for ( int x=10; x<nWidth-10; x+=GRIDSIZE )
	{
		for ( int y=10; y<nHeight-10; y+=GRIDSIZE )
		{
			int nConverted = pCornerInfo->GetConverted(std::pair<int,int>(x,y), nImageNum);
            dRet += ((BYTE)ppImageArrays[nImageNum][nConverted]);
		}
	}

	int nWidthCnt=0, nHeightCnt=0;
	for ( int x=10; x<nWidth-10; x+=GRIDSIZE ) nWidthCnt++;
	for ( int y=10; y<nHeight-10; y+=GRIDSIZE ) nHeightCnt++;

	dRet /= (nWidthCnt*nHeightCnt);
	return dRet;
}
bool SNU_GetAverageRGB(const CString& strPath, int nImageNum, double& dRet)
{
	bool bRet = false;
	dRet = 0.0;
	char** ppImageArrays = NULL;
	do
	{
		int nSum = 0;
        
		ppImageArrays = SNU_allocate_image_array();

		if ( !SNU_parse_gbc(strPath, ppImageArrays) )
			break;

		int nWidth=0, nHeight=0;
        CCornerInfo* pCornerInfo = SNU_detect_corner_norotate(ppImageArrays);
		if ( !pCornerInfo )
			break;

		dRet = SNU_GetAverageRGB_InArray(ppImageArrays, pCornerInfo, nImageNum);
        delete pCornerInfo;
		bRet = true;
	} while(0);

    SNU_free_image_array(ppImageArrays);
	return bRet;
}

void SNU_GenerateDeinkedScript_Recursively(const CString& strPath, int nBillType, int nBillDirection, std::vector<CScriptLine>& vecScriptLines)
{
    CFileFind finder;
    BOOL bWorking = finder.FindFile(strPath + _T("\\*.*"));

    while (bWorking)
    {
        bWorking = finder.FindNextFile();

        if (finder.IsDots())
            continue;

        if (finder.IsDirectory())
        {
            //CString strDirPath = finder.GetFilePath();
            //SNU_GenerateDeinkedScript_Recursively(strPath, nBillType, nBillDirection, vecScriptLines);
        }
        else
        {
            CString strFilePath = finder.GetFilePath();
            if ( strFilePath.Right(4).CompareNoCase(_T(".gbc")) == 0 )
            {
				CScriptLine scriptline(strFilePath, nBillType, nBillDirection);
				vecScriptLines.push_back(scriptline);
            }
        }
    }
    finder.Close();
}
void SNU_GetLearData_Recursively(const CString& strPath, int nBillType, int nBillDirection)
{
    CFileFind finder;
    BOOL bWorking = finder.FindFile(strPath + _T("\\*.*"));

    while (bWorking)
    {
        bWorking = finder.FindNextFile();

        if (finder.IsDots())
            continue;

        if (finder.IsDirectory())
        {
            CString strDirPath = finder.GetFilePath();
            SNU_GetLearData_Recursively(strDirPath, nBillType, nBillDirection);
        }
        else
        {
            CString strFilePath = finder.GetFilePath();
            if ( strFilePath.Right(4).CompareNoCase(_T(".gbc")) == 0 )
            {
				bool bDone = true;
				for ( int i=0; i<8; i++ )
				{
					double dRet = 0;
					if ( !SNU_GetAverageRGB(strFilePath, i, dRet) )
						bDone = false;
					else
						SNU_g_adAverages[nBillType][nBillDirection][i] += dRet;
				}
				if ( bDone )
					SNU_g_anCnt[nBillType][nBillDirection]++;
            }
        }
    }
    finder.Close();
}

bool SNU_GenerateDeinkedScript()
{
	std::vector<CScriptLine> vecScriptlines;
	CString strRootPath = _T("D:\\billchecker\\Samples\\EURO_New");
	for ( int nBillType=0; nBillType<NUM_OF_BILLTYPES; nBillType++ )
	{
		CString strBillType;
		switch ( nBillType )
		{
		case BILLTYPE_EURO_5 : strBillType = _T("5"); break;
		case BILLTYPE_EURO_10 : strBillType = _T("10"); break;
		case BILLTYPE_EURO_20 : strBillType = _T("20"); break;
		case BILLTYPE_EURO_50 : strBillType = _T("50"); break;
		case BILLTYPE_EURO_100 : strBillType = _T("100"); break;
		case BILLTYPE_EURO_200 : strBillType = _T("200"); break;
		case BILLTYPE_EURO_500 : strBillType = _T("500"); break;
		}
		if ( strBillType.IsEmpty() ) 
			continue;

		for ( int nBillDirection=0; nBillDirection<NUM_OF_BILLDIRECTION; nBillDirection++ )
		{
			CString strBillDirection;
			switch ( nBillDirection )
			{
			case BILLDIRECTION_FT : strBillDirection = _T("FT"); break;
			case BILLDIRECTION_FB : strBillDirection = _T("FB"); break;
			case BILLDIRECTION_BT : strBillDirection = _T("BT"); break;
			case BILLDIRECTION_BB : strBillDirection = _T("BB"); break;
			}
			if ( strBillDirection.IsEmpty() )
				continue;
			CString strPath;
			strPath.Format(_T("%s\\%s\\%s"), strRootPath, strBillType, strBillDirection);
			SNU_GenerateDeinkedScript_Recursively(strPath, nBillType, nBillDirection, vecScriptlines);
		}
	}

	FILE* pFile = fopen(_T("right_answers.txt"), "w");
	fprintf(pFile, "%d\n", vecScriptlines.size());
	fprintf(pFile, "\"\"\n");
	for ( std::vector<CScriptLine>::iterator iter=vecScriptlines.begin(); iter!=vecScriptlines.end(); iter++ )
	{
		CString strBillType;
		switch ( iter->GetBillType() )
		{
		case BILLTYPE_EURO_5 : strBillType = _T("EURO5"); break;
		case BILLTYPE_EURO_10 : strBillType = _T("EURO10"); break;
		case BILLTYPE_EURO_20 : strBillType = _T("EURO20"); break;
		case BILLTYPE_EURO_50 : strBillType = _T("EURO50"); break;
		case BILLTYPE_EURO_100 : strBillType = _T("EURO100"); break;
		case BILLTYPE_EURO_200 : strBillType = _T("EURO200"); break;
		case BILLTYPE_EURO_500 : strBillType = _T("EURO500"); break;
		}
		CString strBillDirection;
		switch ( iter->GetBillDirection() )
		{
		case BILLDIRECTION_FT : strBillDirection = _T("FT"); break;
		case BILLDIRECTION_FB : strBillDirection = _T("FB"); break;
		case BILLDIRECTION_BT : strBillDirection = _T("BT"); break;
		case BILLDIRECTION_BB : strBillDirection = _T("BB"); break;
		}
		fprintf(pFile,_T("\"%s\"\t%s\t%s\n"),iter->GetPath(), strBillType, strBillDirection);
	}
	fclose(pFile);
	return true;
}

bool SNU_LearnDeinkedData()
{
	CString strRootPath = _T("D:\\billchecker\\Samples\\EURO_New");
	for ( int nBillType=0; nBillType<NUM_OF_BILLTYPES; nBillType++ )
	{
		CString strBillType;
		switch ( nBillType )
		{
		case BILLTYPE_EURO_5 : strBillType = _T("5"); break;
		case BILLTYPE_EURO_10 : strBillType = _T("10"); break;
		case BILLTYPE_EURO_20 : strBillType = _T("20"); break;
		case BILLTYPE_EURO_50 : strBillType = _T("50"); break;
		case BILLTYPE_EURO_100 : strBillType = _T("100"); break;
		case BILLTYPE_EURO_200 : strBillType = _T("200"); break;
		case BILLTYPE_EURO_500 : strBillType = _T("500"); break;
		}
		if ( strBillType.IsEmpty() ) 
			continue;
		for ( int nBillDirection=0; nBillDirection<NUM_OF_BILLDIRECTION; nBillDirection++ )
		{
			CString strBillDirection;
			switch ( nBillDirection )
			{
			case BILLDIRECTION_FT : strBillDirection = _T("FT"); break;
			case BILLDIRECTION_FB : strBillDirection = _T("FB"); break;
			case BILLDIRECTION_BT : strBillDirection = _T("BT"); break;
			case BILLDIRECTION_BB : strBillDirection = _T("BB"); break;
			}
			if ( strBillDirection.IsEmpty() ) 
				continue;
			CString strPath;
			strPath.Format(_T("%s\\%s\\%s"), strRootPath, strBillType, strBillDirection);
			SNU_GetLearData_Recursively(strPath, nBillType, nBillDirection);
		}
	}

	for ( int i=0; i<NUM_OF_BILLTYPES; i++ )
		for ( int j=0; j<NUM_OF_BILLDIRECTION; j++ )
			for ( int k=0; k<8; k++ )
				if ( SNU_g_anCnt[i][j] > 0 )
					SNU_g_adAverages[i][j][k] /= SNU_g_anCnt[i][j];
	return true;
}

bool SNU_SerializeDeinkedTestData_ToFile(const std::string& strOutfilePath)
{
	FILE* pFile = fopen(strOutfilePath.c_str(), "w");
	if ( pFile )
	{
		for ( int i=0; i<NUM_OF_BILLTYPES; i++ )
			for ( int j=0; j<NUM_OF_BILLDIRECTION; j++ )
			{
				fprintf(pFile,"%d ", SNU_g_anCnt[i][j]);
			}
		for ( int i=0; i<NUM_OF_BILLTYPES; i++ )
			for ( int j=0; j<NUM_OF_BILLDIRECTION; j++ )
				for ( int k=0; k<8; k++ )
				{
					fprintf(pFile, "%f ", SNU_g_adAverages[i][j][k]);
				}
		fclose(pFile);
		return true;
	}
	else
		return false;
}

bool SNU_InitDeinkedTestData_FromFile(const std::string& strOutfilePath)
{
	FILE* pFile = fopen(strOutfilePath.c_str(), "r");
	if ( pFile )
	{
		for ( int i=0; i<NUM_OF_BILLTYPES; i++ )
			for ( int j=0; j<NUM_OF_BILLDIRECTION; j++ )
			{
				fscanf(pFile,"%d ", &SNU_g_anCnt[i][j]);
			}
		for ( int i=0; i<NUM_OF_BILLTYPES; i++ )
			for ( int j=0; j<NUM_OF_BILLDIRECTION; j++ )
				for ( int k=0; k<8; k++ )
				{
					float fData;
					fscanf(pFile, "%f", &fData);
					SNU_g_adAverages[i][j][k] = fData;
				}
		fclose(pFile);
		return true;
	}
	else
		return false;
}


bool SNU_PREPROCESS_DEINKED() 
{
	for ( int i=0; i<NUM_OF_BILLTYPES; i++ )
		for ( int j=0; j<NUM_OF_BILLDIRECTION; j++ )
			for ( int k=0; k<8; k++ )
			{
				SNU_g_adAverages[i][j][k] = 0;
				SNU_g_anCnt[i][j] = 0;
			}

	for ( int i=0; i<NUM_OF_BILLTYPES; i++ )
		for ( int j=0; j<NUM_OF_BILLDIRECTION; j++ )
		{
			SNU_g_adThreshHold[i][j] = 18;
			SNU_g_adSoilThreshHold[i][j] = 11.2;
		}
//	for ( int j=0; j<NUM_OF_BILLDIRECTION; j++ )
//		SNU_g_adThreshHold[BILLTYPE_EURO_50][j] = 5;

	//SNU_GenerateDeinkedScript();
	//SNU_LearnDeinkedData();
	//SNU_SerializeDeinkedTestData_ToFile("deink_data");
	SNU_InitDeinkedTestData_FromFile("deink_data");
	return true;
}

bool SNU_CHECK_FITNESS_DEINKED(char** ppImageArrays, CCornerInfo* pCornerInfo, int nBillType, int nBillDirection) 
{
	if ( nBillType >= BILLTYPE_EURO_5 && nBillType <= BILLTYPE_EURO_500 )
	{
		double dVal0 = SNU_GetAverageRGB_InArray(ppImageArrays, pCornerInfo, 0);
		double dVal4 = SNU_GetAverageRGB_InArray(ppImageArrays, pCornerInfo, 4);
		//return (dRet <= SNU_g_adAverages[nBillType][nBillDirection][4] + SNU_g_adThreshHold[nBillType][nBillDirection]);
		bool bRet = (dVal0 <= SNU_g_adAverages[nBillType][nBillDirection][0] + SNU_g_adThreshHold[nBillType][nBillDirection])
			&& (dVal4 <= SNU_g_adAverages[nBillType][nBillDirection][4] + SNU_g_adThreshHold[nBillType][nBillDirection]);
		return bRet;
	}
	else
		return true;
}

bool SNU_CHECK_FITNESS_SOIL(char** ppImageArrays, CCornerInfo* pCornerInfo, int nBillType, int nBillDirection) 
{
	if ( nBillType >= BILLTYPE_EURO_5 && nBillType <= BILLTYPE_EURO_500 )
	{
		double dVal0 = SNU_GetAverageRGB_InArray(ppImageArrays, pCornerInfo, 0);
		double dVal4 = SNU_GetAverageRGB_InArray(ppImageArrays, pCornerInfo, 4);
		bool bRet = (dVal0 >= SNU_g_adAverages[nBillType][nBillDirection][0] - SNU_g_adSoilThreshHold[nBillType][nBillDirection])
			&& (dVal4 >= SNU_g_adAverages[nBillType][nBillDirection][4] - SNU_g_adSoilThreshHold[nBillType][nBillDirection]);
		return bRet;
	}
	else
	{
		return true;
	}
}